package ThreadPool.jike.demo43;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author oyz
 * STM事务实现类
 */
public final class STMTxn implements Txn {


    //事务id生成器
    private static final AtomicLong atomicLong = new AtomicLong(0);

    // 当前事务所有的相关数据
    private Map<TxnRef, VersionedRef> inTxnMap = new HashMap<TxnRef, VersionedRef>();

    // 设置当前事务所有需要修改的数据
    private Map<TxnRef, Object> writeMap = new HashMap<TxnRef, Object>();


    STMTxn() {
        atomicLong.incrementAndGet();
    }

    @Override
    public <T> T getValue(TxnRef<T> txnRef) {
        //将需要读取的数据，加入inTxnMap
        if (!inTxnMap.containsKey(txnRef)) {
            inTxnMap.put(txnRef, txnRef.versionedRef);
        }
        return (T) inTxnMap.get(txnRef);
    }

    @Override
    public <T> void setValue(TxnRef<T> txnRef, T value) {
        //将需要修改的数据加入inTxnMap
        if (!inTxnMap.containsKey(txnRef)) {
            inTxnMap.put(txnRef, txnRef.versionedRef);
        }
        writeMap.put(txnRef, value);
    }

    // 提交事务
    boolean commit() {
        synchronized (STM.lock) {
            boolean isValid = false;
            //校验所有读过的数据是否发生过变化
            for (Map.Entry<TxnRef, VersionedRef> entry : inTxnMap.entrySet()) {
                VersionedRef curRef = entry.getKey().versionedRef;
                VersionedRef readRef = entry.getValue();
                //通过版本号来验证数据是否发生过变化
                if (curRef.getVersion() != readRef.getVersion()) {
                    isValid = false;
                    break;
                }
            }
            //如果校验通过，则所有更改生效
            if (isValid) {
                writeMap.forEach((k, v) -> {
                    k.versionedRef = new VersionedRef(v, atomicLong.get());
                });
            }
            return false;
        }

    }


}
